
// Object.freeze() 冻结一个对象
// Object.isFrozen() 判断一个对象是否被冻结

// function Test() {
//   this.a = 1;
//   this.b = 2;
// }

// Test.prototype.c = 3;

// const test = new Test();
// console.log(test);

// test.d = 444

// const newTest = Object.freeze(test);
// console.log(newTest);
// console.log(newTest === test); // true 同一个引用值

// Object.freeze(test);

// console.log(test.a); // 可读
// test.a = 111;
// console.log(test); // 不可修改
// delete test.a
// console.log(test); // 不可删除
// test.d = 444
// console.log(test); // 不可扩展
// for (let i in test) {
  // console.log(test[i], i); // 可枚举
// }
// Test.prototype.c = 333; // 通过构造函数原型属性更改其属性是可以的
// test.__proto__.c = 333; // 通过对象的proto属性更改原型上的属性是可以的

// Test.prototype = { // 原型对象 不可更改
//   a: 111,
//   b: 222,
//   c: 333
// }
// test.__proto__ = { // 原型不可修改(重写)
//   a: 111,
//   b: 222,
//   c: 333
// }
// console.log(test);

// const obj = {
//   _a: 1,
//   b: 2,
//   c: {
//     d: 3
//   },
//   get a() {
//     return this._a;
//   },
//   set a(newVal) {
//     this._a = newVal;
//   }
// }
// Object.freeze(obj);
// obj.a = 2; // 不可修改
// obj.c.d = 444; // 可修改
// console.log(obj);

// const arr = [1, 2, 3];
// arr = {
//   '0': 1,
//   '1': 2,
//   '3': 3
// }

// Object.freeze(arr);
// console.log(arr[1]); // 可读
// arr[2] = 222; // 不可写
// arr.push(4); // 报错 不可扩展
// arr.splice(2, 1); // 报错 不可删除
// console.log(arr);
// function fail(a) {
  // "use strict" // 严格模式下都会报错
  // a[0] = 111; // 不可修改
  // a.push(2); // 报错 不可扩展
  // console.log(a);
// }
// fail(arr);


// Object.isFrozen()

// 'use strict'

// const obj = {
//   a: 1,
//   b: 2,
//   c: {
//     d: 3
//   }
// }

// Object.freeze(obj);

// const res = Object.isFrozen(obj);
// console.log(res); // true

// 一个不可扩展的空对象同时也是一个冻结对象
// const vacuouslyFrozen = Object.preventExtensions({});
// console.log(Object.isFrozen(vacuouslyFrozen)); // true

// obj.a = 2;

// console.log(obj);


/**
 * Object.freeze() 冻结一个对象
 * 
 * 1. 返回原对象
 * 
 * 2. 对象的属性不可扩展、不可删除、不可修改(访问器属性getter和setter同样)、可读
 * 
 * 3. 对象的原型不可修改，但原型的属性可修改
 * 
 * 4. 严格模式下 或使用 Object.defineProperty 会报错 对象的属性是只读的
 * 
 * 5. 传如的参数不是一个对象(原始值) ES5 中会报错，ES2015会把参数本身简单的返回
 * 
 * 6. 数组作为一种对象，被冻结，其元素不能被修改。没有数组元素可以被添加或移除。
 * 
 * 7. 用Object.seal()密封的对象可以改变它们现有的属性。
 *      使用Object.freeze() 冻结的对象中现有属性是不可变的。
 * 
 * 8. Object.freeze()是浅冻结
 */


// 实现深冻结

const obj = {
  a: 1,
  b: 2,
  c: {
    d: 3,
    e: {
      f: 4
    }
  }
}

Object.deepFreeze = function(obj) {

  var _keyArr = Object.getOwnPropertyNames(obj);

  if (_keyArr.length) {
    _keyArr.forEach(v => {
      var _value = obj[v]
      if (typeof _value === 'object' && _value !== null) {
        Object.deepFreeze(_value);
      } 
    })
  }

  return Object.freeze(obj)
}

console.log(obj);

const newObj = Object.deepFreeze(obj);
newObj.a = 222; // 不可修改
newObj.c.d = 444; // 可修改

delete newObj.c.e.f
console.log(newObj);